;;; This is the IDE's built-in-editor, where you create and edit
;;; lisp source code.  You could use some other editor instead,
;;; though the IDE's menu-bar commands would not be applicable there.
;;; 
;;; This editor has a tab for each file that it's editing.  You can
;;; create a new editor buffer at any time with the File | New command.
;;; Other commands such as Search | Find Definitions will create
;;; editor buffers automatically for existing code.
;;; 
;;; You can use the File | Compile and Load command to compile and
;;; load an entire file, or compile an individual definition by
;;; placing the text cursor inside it and using Tools | Incremental
;;; Compile.  You can similarly evaluate test expressions in the
;;; editor by using Tools | Incremental Evaluation; the returned
;;; values and any printed output will appear in a lisp listener
;;; in the Debug Window.
;;; 
;;; For a brief introduction to other IDE tools, try the
;;; Help | Interactive IDE Intro command.  And be sure to explore
;;; the other facilities on the Help menu.

;;; (c) Phillip Abbott 2010.
;;; This program shall forever be known as "Krish's good RPN programmer"





(defun prompt-read (n)
  (princ n)
  (princ #\newline)
  (princ ">")
  (read-line))

(defparameter *rpn-data*
  `( :criticality (
                   (1 (cosmetic or enhancement) 
                    (typo or new feature ))
                   (2 (workaround exists) 
                    (there exists an alternative way that the user can achieve the same functionality e.g. option does not appear on the main menu but is still in the maintenance menu))
                   (3 (correctness issue) 
                    (program displays incorrect information e.g. shows 14 C when the actual temp is 13 C))
                   (4 (load loss) 
                    ( the problem could lead to the unit being off when it should be on) )
                  (5 (safety) (the problem could lead to the unit being on when it should be off ))
                  )
                
  :customer-use (
                  (1 (rarely 0-10%)) 
                  (2 (seldom 10-35%)) 
                  (3 (occasionally 35-65%)) 
                  (4 (usually 65-90%)) 
                  (5 (always 90-100%)) 
                  )
                 
  :visibility (
                  (1 (isolated internal observation) )
                  (2 (irreproducible customer observation) )
                  (3 (reproducible internal observation) )
                  (4 (intermittent customer observation) )
                  (5 (repeatable customer observation) )
                  )
  :legacy-item (
                  (1 (new feature request) )
                  (2 (exists on old platforms) )
                  (3 (exists in multiple previous releases) )
                  (4 (broken in most recent release) )
                  (5 (broken in pending release) )
                  )
                 
  :complexity (
                  (1 (science project) )
                  (2 (new module creation) )
                  (3 (multiple lines in multiple modules) )
                  (4 (multiple lines in single module) )
                  (5 (one liner) )
                  )
  :in-scope(
                  (0 (out of scope) )
                  (5 (in scope) )
                 
                 )  ) )

(defun rpn-parameters (&optional (rpn-data *rpn-data*) )
  (if rpn-data
      (let* (
            ( c (car rpn-data) )
            ( l (list c) )
            ( d (cddr rpn-data) )
            ( ll (rpn-parameters d) )
             )
        (append l ll)
        
        )
    rpn-data))

(defparameter *weights* 
  `( :criticality 3
                 :customer-use 1
                 :visibility 2
                 :legacy-item 1
                 :complexity 1
                 :in-scope 2
                 ))
  
                  
(defun display-option (l) 
  (princ (car l) )
  (princ ":  ")
  (princ (cadr l))
  (princ #\newline)
  nil
  )

(defun display-options (ll)
  (princ #\newline)
  (mapcan #'display-option ll)
  )

(defun disp-opt (n &optional (rpn-data *rpn-data*) )
  (display-options (getf rpn-data n)))

(defun get-parsed-integer ()
  (let* (
         ( the-string (read-line))
         ( the-number (parse-integer the-string :junk-allowed t))
         ( the-result (if the-number the-number 0))
         )
    the-result
    ))

(defun advice (the-option-info n)
  (third (nth n the-option-info)))

(defun get-advice (the-option-info)
  (princ "get advice on #")
  (princ (advice (get-parsed-integer) the-option-info)))

(defun get-bounded-option (the-option-info &optional (low 1) (high 5))
  (princ "?")
  (let ( (x (get-parsed-integer)))
    (when (equal 0 x) (get-advice the-option-info))
    (if (and (<= x high) (<= low x)) x
      (progn (princ "out-of-range, try again --> ")
        (get-bounded-option low high))
      )))

(defun get-binary-option (low high)
  (princ "?")
  (let ( (x (get-parsed-integer)))
    (if (or (equal x high) (equal low x)) x
      (progn (princ "out-of-range, try again --> ")
        (get-binary-option low high))
      )))

(defparameter *the-code-number* 3478)

(defun read-binary-option (the-category &optional (rpn-data *rpn-data*) )
  (display-options (getf rpn-data the-category))
    (list the-category (get-binary-option 0 5) )
    )  


(defun read-option (the-category &optional (rpn-data *rpn-data*) )
  (let ( (the-category-data (getf rpn-data the-category)))
  (display-options the-category-data)
    (list the-category (get-bounded-option the-category-data ) )
    ))  

(defun read-options (&optional (rpn-data *rpn-data*) )
  (append (read-option :criticality rpn-data)
        (read-option :customer-use rpn-data)
        (read-option :visibility rpn-data)
        (read-option :legacy-item rpn-data)
        (read-option :complexity rpn-data)
        (read-binary-option :in-scope rpn-data)
          ))



; precondition:  this function assumes that all these have the same lengths:

(defun calc-rpn ( l &optional (w *weights*) (p (rpn-parameters)) )
  (if p
      (let* (
             ( pp (car p) ) ; get the parameter
             ( lx (getf l pp)) ; get the value for that parameter from the list
             ( wx (getf w pp)) ; get the weight of that parameter
             ( m (* lx wx) ) ; multiply them
             ( ld (cddr l) ) ; denude the list
             ( wd (cddr w) ) ; denude the weights
             ( pd (cdr p) ) ; denude the parameters
             )
        ; (print m)
        (+ m (calc-rpn ld wd pd))
        
        )
    0
    ))


; usage (get-description :visibility x)
; (eq x (:CRITICALITY 3 :CUSTOMER-USAGE 4 :VISIBILITY 5 :LEGACY 4 :COMPLEXITY 3 ...)
(defun get-description ( p l &optional (rpn-data *rpn-data*) )
  (let* (
         ( n (getf l p) )
         ( ll (getf rpn-data p))
         ( x (find n ll :key #'car))
         ( d (cadr x))
         )
    d
    ))

; usage (get-all-descriptions x)
; (eq x (:CRITICALITY 3 :CUSTOMER-USAGE 4 :VISIBILITY 5 :LEGACY 4 :COMPLEXITY 3 ...)
(defun get-all-descriptions ( l &optional (rpn-data *rpn-data*) (p (rpn-parameters)) )
  (if p
      (let* (
             ( pp (car p) ) ; get the parameter
             ( lx (getf l pp)) ; get the value for that parameter from the list
             ( desc (get-description pp l rpn-data))
             ( ld (cddr l) ) ; denude the list
             ( pd (cdr p) ) ; denude the parameters
             )
        (cons  ( list pp lx desc) (get-all-descriptions ld rpn-data pd) )
        
        ) ;end let
    nil
    ))




; helper function for get-rpn
(defun print-description (n &optional html)
  (when html (princ "<li>"))
  (when html (princ "<b>"))
  (princ (car n))
  (when html (princ "</b>"))
  (princ #\tab)
  
  (when html (princ "<i>"))
  (princ (cadr n))
  (when html (princ "</i>"))
  (princ #\tab)
  
  
  (mapcar #'(lambda (q) 
              (princ q)
              (princ #\tab)
              ; (princ #\tab)
              )
    (cddr n))

  (when html (princ "<p>") )
  
  (when html (princ "</li>"))
  (princ #\newline)
  )

; helper function for get-rpn
(defun rpn-advice (n)
  (if (< n 24) "defer!"
    (if (< n 32) "probably defer"
      (if (< n 35) "don't know"
        "include!"))))

; helper function for get-rpn
(defun pretty-pair-printer (the-key the-value)
  (princ the-key)
  (princ #\tab)
  (princ "=")
  (princ #\tab)
  (princ the-value)
  (princ #\newline)
  )



(defun describe-rpn (the-options &optional html (rpn-data *rpn-data*) (w *weights*) (p (rpn-parameters)))
  (flet ( (new-line () (when html (princ "<p>")) (princ #\newline)))
  (let* (
         ( v   (calc-rpn the-options w p) )
         ( result (get-all-descriptions the-options rpn-data p) )
         )
    
    (new-line)
    (when html (princ "<ul>"))
    (mapcar  #'(lambda (n) (print-description n html)) result)
    (when html (princ "</ul>"))
    (new-line)
    (pretty-pair-printer "rpn      " v)
    (when html (princ "<p>"))
    (pretty-pair-printer "recommend" (rpn-advice v))
    (unless html ; don't bother printing the chart to html; it doesn't look good.
      (new-line)
      (princ "         1         2         3         4         5<p>")
      (new-line)
      (princ "12345678901234567890123456789012345678901234567890")
      (new-line)
      (princ "XXXXXXXm---------------========???!!!!!!!!!!!!!!!M")
      (new-line)
      (loop repeat v do (princ " "))
      (princ "^")
      (new-line)
      )
    v ; return the raw rpn
  )))

(defun write-rpn (the-file-name &optional (html t) (rpn-data *rpn-data*) (w *weights*) (p (rpn-parameters)))
  (let* (
         ( the-options (read-options rpn-data))
         )
    
    (with-open-file 
        (out the-file-name :direction :output :if-exists :supersede)
      (let ( (*standard-output* out) )
        ( describe-rpn the-options html rpn-data w p)
        ))))

  
  




; this is the main function 
(defun get-rpn (&optional html (rpn-data *rpn-data*) (w *weights*) (p (rpn-parameters)))
  (let* (
         ( the-options (read-options rpn-data))
         )
    ( describe-rpn the-options html rpn-data w p)
  ))

; test the get-rpn function with random values
(defun test-rpn (&optional html)
  (let ( (the-test-values (loop repeat 5 collecting (+ 1 (random 5)))))
  (let ( (the-test-string (format nil "~{~a~%~}" (append the-test-values (list 5)))))
  (with-input-from-string (in the-test-string) 
    (let ((*standard-input* in)) 
      (if html 
          (progn (write-rpn "D:/r/rpn.html")
            (r-run::do-run "explorer D:\\r\\rpn.html"))
      (get-rpn )
      ))))))



  
  
    
    